package demo.platform;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;

import java.util.Collections; // For min/max values.
import java.util.Arrays;

import javax.swing.JPanel;

public class Field extends JPanel implements ActionListener, Runnable, Constants {

	private Player player;
	private Thread thread1;
	private Tile groundTile;
	private ArrayList<Tile> mapTiles;
	
	//TODO: Rewrite collision code to use rectangles from Tile array?
	private ArrayList<Rectangle> screenGrid; // For collisions.
	
	
	public Field() {
		addKeyListener(new kAdapter());
		setFocusable(true);
		setBackground(Color.white);
		setDoubleBuffered(true);
		setSize(1024, 768);
		
		
		
		initGame();
		
	}
	
	private void initGame() {
		player = new Player();
		initTiles();
	}
	
	private void initTiles() {
		groundTile = new Tile(0,704,"Ground1.png");
		
		mapTiles = new ArrayList<Tile>();
		screenGrid = new ArrayList<Rectangle>();
		
		for (int i = 0; i < NUM_TILES_X; i++) {
			
			for (int k = 0; k < NUM_TILES_Y; k++) {
				screenGrid.add(new Rectangle(i*BASE_TILE_SIZE, k*BASE_TILE_SIZE, 
						BASE_TILE_SIZE, BASE_TILE_SIZE));
				if (SAMPLE_LEVEL[k][i] == 1) {
					mapTiles.add(new Tile(i*BASE_TILE_SIZE, k*BASE_TILE_SIZE, "aTile.png"));
				}
				
				if (SAMPLE_LEVEL[k][i] == 2) {
					mapTiles.add(new Tile(i*BASE_TILE_SIZE, k*BASE_TILE_SIZE, "aTile2.png"));
				}
			}
		}
		
		
	}
	
	public void addNotify() {
		super.addNotify();
		thread1 = new Thread(this);
		thread1.start();
	}
	
	// These make sure that the window toolkit presents
	// our screen the way we want it to.
	@Override
	public Dimension getPreferredSize() {
		return new Dimension(1024, 768);
	}
	
	@Override
    public Dimension getMinimumSize() {
        return getPreferredSize();
    }

    @Override
    public Dimension getMaximumSize() {
        return getPreferredSize();
    }
	
    // End window size.
    
    
	public void paint(Graphics g) {
		super.paint(g);
		Graphics2D g2d = (Graphics2D)g;
		
		g2d.drawImage(player.getEntitySprite(), player.getEntityX(), player.getEntityY(), null);
		g2d.drawImage(groundTile.getTile(), groundTile.getX(), groundTile.getY(), null);
		
		// Test
		if (player.getCollisions() != null) {
			g2d.setColor(Color.CYAN);
			for (int i = 0; i < player.getCollisions().length; i++) {
				g2d.fill(player.getCollisions()[i]);
			}
			g2d.setColor(Color.black);
		}
		
		
		// Paint grid on screen.
		for (int i = 0; i < screenGrid.size(); i++) {
			Rectangle r = screenGrid.get(i);
			g2d.draw(r);
		}
		
		// Paint tiles to screen.
		for (int d = 0; d < mapTiles.size(); d++) {
			Tile t = mapTiles.get(d);
			g2d.drawImage(t.getTile(), t.getX(), t.getY(), null);
		}
		
		// Paint player box (DEBUG)
		g2d.setColor(Color.pink);
		g2d.draw(player.getEntityBounds());
		g2d.drawString("Player X: " + Integer.toString(player.getEntityX()), 50,50);
		g2d.drawString("Player DX: " + Integer.toString(player.getDX()), 50, 100);
		
		// Needed for linux systems to prevent artifacts.
		Toolkit.getDefaultToolkit().sync();
		g.dispose();
	}
	
	public void moveEntities() {
		
	}
	
	public int findMaxMovement(Entity e, int direction) {
		
		Rectangle bounds = e.getEntityBounds();
		
		// Initialize an array holding the tiles that are being
		// collided with. Is [4] because 1x2 sprite can only
		// collide with 4 tiles.
		Rectangle[] collisions = new Rectangle[6];
		for (int q = 0; q < 6; q++) {
			collisions[q] = new Rectangle(0,0);
		}
		
		int k = 0; // Start a counter for rectangles.
		
		// Add location of colliding rectangles to array.
		for (int i = 0; i < screenGrid.size(); i++) {
			if (bounds.intersects(screenGrid.get(i))) {
				collisions[k] = screenGrid.get(i);
				k++;
			}
		}
		
		// Test
			player.setCollisions(collisions);
		// /Test
		
		// Determine their position in level array
		// indexX and indexY contain the coordinates
		// of the tiles the PLAYER is CURRENTLY occupying.
		int[] indexX = {0,0,0,0,0,0};
		int[] indexY = {0,0,0,0,0,0};
		for (int m = 0; m < collisions.length; m++) {
			indexX[m] = collisions[m].x / BASE_TILE_SIZE;
			indexY[m] = collisions[m].y / BASE_TILE_SIZE;
		}
		
		// Now indexX and indexY hold the integer values of the tiles
		// position.
		
		
		// Now determine the closest tile depending on direction.
		// xBox and yBox hold the coordinates of the closest tiles in the
		// scanned direction.
		int xBox[] = {1000,1000,1000,1000,1000,1000};
		int yBox[] = {1000,1000,1000,1000,1000,1000};

		
		
		// Right
		if (direction == 2) {
			int index = 0;
			for (int p = 0; p < indexY.length; p++) { 
				//for (int q = 0; q < NUM_TILES_X - indexX[0]; q++) { // I was doing something stupid here.
				// The following is correct.
				for (int q = indexX[0]; q < NUM_TILES_X; q++) {
					if (SAMPLE_LEVEL[indexY[p]][q] == 2 && xBox[index] == 1000) { // Will be replacing this with a solid fag.
					
						xBox[index] = q;
						
						
						
					}
				}
				index++;
			}
		}
		
		// Left
		if (direction == 4) {
			int index = 0;
			for (int p = 0; p < indexY.length; p++) {
				for (int q = indexX[0]; q > 0; q--) {
					if (SAMPLE_LEVEL[indexY[p]][q] == 2 && xBox[index] == 1000) {
						xBox[index] = q;
					}
				}
				index++;
			}
		}
		
		
		// Up
		if (direction == 1) {
			int index = 0;
			for (int p = 0; p < indexX.length; p++) {
				
			}
		}
				
				
		// Determine closest obstacle:
				
		Arrays.sort(xBox);
		int[] blank = {1000,1000,1000,1000,1000,1000};
		boolean isThereATile = false;
		
		if (Arrays.equals(xBox, blank))
			isThereATile = false;
		else isThereATile = true;
		int tileCX = xBox[0]*32 - 32; // -32 to make the player hit on the left side.
		
		// Need to get highest non 1000 value since we're moving left.
		int temp = xBox[0]; // Default xBox[0] otherwise if there's only one tile collisions fail.
		for (int i = 0; i < xBox.length -1; i++) {
			// xBox is already sorted. Must be!
			if (xBox[i+1] > xBox[i] && xBox[i+1] != 1000) {
				temp = xBox[i+1]; // This is the largest tile value (farthest right).
			}
			
		}
		
		int tileCXRight = temp*32 + 32;
		
		int maxMovement = 0;
		int compare = player.getEntityX() + player.getDX();
		if (direction == 2 && (player.getEntityX() + player.getDX()) > tileCX && isThereATile) {
		//if (direction == 2 && (player.getRightX() + player.getDX()) > tileCX && isThereATile) {
			player.setDX(player.getEntityX()-tileCX);
			maxMovement = player.getEntityX() - tileCX;
		}
		
		if (direction == 4 && (compare) < tileCXRight && isThereATile) {
			player.setDX(tileCXRight - player.getEntityX());
		}
		
		if (direction == 4){
			direction = direction + 1 -1;
		}
		
		return 1;
	}
	
	public void checkCollisions(Entity e) {
		Rectangle entityRect = e.getEntityBounds();
		
		
	}
	
	private class kAdapter extends KeyAdapter {
		@Override
		public void keyPressed(KeyEvent e) {
			player.keyPressed(e);
		}
		
		@Override
		public void keyReleased(KeyEvent e) {
			player.keyReleased(e);
		}
	}

	@Override
	public void actionPerformed(ActionEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void run() {
		
		long beforeTime, timeDiff, sleep;
		
		beforeTime = System.currentTimeMillis();
		
		while(!player.isEntityDead()) {
			
			repaint();
			findMaxMovement(player, player.getDirection());
			player.move();
			timeDiff = System.currentTimeMillis() - beforeTime;
			sleep = 5 - timeDiff;
			if (sleep < 0)
				sleep = 2;
			try {
				Thread.sleep(sleep);
			} catch (InterruptedException e) {
				System.out.println("Sleep interrupted");
			}
	
			beforeTime = System.currentTimeMillis();
		}
		
	}
}
